[Python-checkins] CVS: python/dist/src/PC w9xpopen.c,1.2,1.2.6.1

Anthony Baxter anthonybaxter@users.sourceforge.net
Sun, 07 Apr 2002 21:42:12 -0700


Update of /cvsroot/python/python/dist/src/PC
In directory usw-pr-cvs1:/tmp/cvs-serv18851/PC

Modified Files:
      Tag: release21-maint
	w9xpopen.c 
Log Message:
Backport of bug 
457466: "popenx() argument mangling hangs python" [Win9x only]."

Can't test this myself, but MarkH sez it's ok.



Index: w9xpopen.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/PC/w9xpopen.c,v
retrieving revision 1.2
retrieving revision 1.2.6.1
diff -C2 -d -r1.2 -r1.2.6.1
*** w9xpopen.c	14 Aug 2000 05:04:28 -0000	1.2
--- w9xpopen.c	8 Apr 2002 04:42:09 -0000	1.2.6.1
***************
*** 17,23 ****
  #define WINDOWS_LEAN_AND_MEAN
  #include <windows.h>
  
  const char *usage =
! "This program is used by Python's os.pipe function to\n"
  "to work around a limitation in Windows 95/98.  It is\n"
  "not designed to be used as stand-alone program.";
--- 17,24 ----
  #define WINDOWS_LEAN_AND_MEAN
  #include <windows.h>
+ #include <stdio.h>
  
  const char *usage =
! "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.";
***************
*** 29,37 ****
      PROCESS_INFORMATION pi;
      DWORD exit_code=0;
  
!     if (argc != 2) {
!         MessageBox(NULL, usage, argv[0], MB_OK);
          return 1;
      }
  
      /* Make child process use this app's standard files. */
--- 30,83 ----
      PROCESS_INFORMATION pi;
      DWORD exit_code=0;
+     int cmdlen = 0;
+     int i;
+     char *cmdline, *cmdlinefill;
  
!     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. */
***************
*** 44,48 ****
  
      bRet = CreateProcess(
!         NULL, argv[1],
          NULL, NULL,
          TRUE, 0,
--- 90,94 ----
  
      bRet = CreateProcess(
!         NULL, cmdline,
          NULL, NULL,
          TRUE, 0,
***************
*** 50,53 ****
--- 96,101 ----
          &si, &pi
          );
+ 
+     free(cmdline);
  
      if (bRet) {