[Python-checkins] r51485 - in sandbox/trunk/setuptools: launcher.c setuptools/cli.exe setuptools/gui.exe setuptools/tests/__init__.py setuptools/tests/win_script_wrapper.txt

jim.fulton python-checkins at python.org
Tue Aug 22 21:42:49 CEST 2006


Author: jim.fulton
Date: Tue Aug 22 21:42:48 2006
New Revision: 51485

Added:
   sandbox/trunk/setuptools/setuptools/tests/win_script_wrapper.txt
      - copied unchanged from r51481, sandbox/branches/jim-fix-setuptools-cli/setuptools/setuptools/tests/win_script_wrapper.txt
Modified:
   sandbox/trunk/setuptools/launcher.c
   sandbox/trunk/setuptools/setuptools/cli.exe
   sandbox/trunk/setuptools/setuptools/gui.exe
   sandbox/trunk/setuptools/setuptools/tests/__init__.py
Log:
Added quoting of script arguments and extended the quoting logic to
handle embedded quotes.

Added support for passing a single argument on the shebang line to
pass things like -O and -i.

Fixed bug in handling trailing whitespace in Python command.


Modified: sandbox/trunk/setuptools/launcher.c
==============================================================================
--- sandbox/trunk/setuptools/launcher.c	(original)
+++ sandbox/trunk/setuptools/launcher.c	Tue Aug 22 21:42:48 2006
@@ -33,22 +33,80 @@
     fprintf(stderr, format, data);
     return 2;
 }
+
 char *quoted(char *data) {
-    char *result = calloc(strlen(data)+3,sizeof(char));
-    strcat(result,"\""); strcat(result,data); strcat(result,"\"");
+    int i, l = strlen(data), nb;
+    /* We allocate twice as much space as needed to deal with worse-case
+       of having to escape everything. */
+    char *result = calloc(l*2+3, sizeof(char));
+    char *presult = result;
+
+    *presult++ = '"';
+    for (nb=0, i=0; i < l; i++)
+      {
+        if (data[i] == '\\')
+          nb += 1;
+        else if (data[i] == '"')
+          {
+            for (; nb > 0; nb--)
+              *presult++ = '\\';
+            *presult++ = '\\';
+          }
+        else
+          nb = 0;
+        *presult++ = data[i];
+      }
+    for (; nb > 0; nb--)        /* Deal w trailing slashes */
+      *presult++ = '\\';
+
+    *presult++ = '"';
+    *presult++ = 0;
     return result;
 }
 
+char *getpyopt(char *python)
+{
+  /* Search a Python command string, read from a #! line for an
+     option.  An option must be separated from an executable name by
+     one or more spaces.  An option consistes of a hyphen followed by
+     one or more letters.
+   */
+  static char *letters = 
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    ;
+  char *p = python + strlen(python) - 1;
+  if (strchr(letters, *p) == NULL)
+    return NULL; /* Path doen't end with a letter. Odd. */
+  while (p > python && strchr(letters, *p) != NULL)
+    p--;
+  if (p == python || *p != '-')
+    return NULL;                /* Can't be an option */
+  p--;
+  if (p > python && isspace(*p))
+    { /* BINGO, we have an option */
+      char *pyopt = p+1;
+      /* strip trailing spaces from remainder of python command */
+      while (p > python && isspace(*p))
+        *p-- = '\0';
+      return pyopt;
+    }
+  else
+    return NULL;
+}
+
 int run(int argc, char **argv, int is_gui) {
 
     char python[256];   /* python executable's filename*/
+    char *pyopt;        /* Python option */
     char script[256];   /* the script's filename */
 
     HINSTANCE hPython;  /* DLL handle for python executable */
     int scriptf;        /* file descriptor for script file */
 
-    char **newargs;     /* argument array for exec */
+    char **newargs, **newargsp; /* argument array for exec */
     char *ptr, *end;    /* working pointers for string manipulation */
+    int i;              /* loop counter */
 
     /* compute script name from our .exe name*/
     GetModuleFileName(NULL, script, sizeof(script));
@@ -73,13 +131,16 @@
             *ptr='\\';  /* convert slashes to avoid LoadLibrary crashes... */
     }
 
-    *ptr = '\0';
+    *ptr-- = '\0';
     while (ptr>python && isspace(*ptr)) *ptr-- = '\0';  /* strip trailing sp */
     if (strncmp(python, "#!", 2)) {
         /* default to python.exe if no #! header */
         strcpy(python, "#!python.exe");
     }
 
+    /* Check for Python options */
+    pyopt = getpyopt(python);
+
     /* At this point, the python buffer contains "#!pythonfilename" */
 
     /* Using spawnv() can fail strangely if you e.g. find the Cygwin
@@ -94,12 +155,19 @@
 
     /* printf("Python executable: %s\n", python); */
 
-    /* Argument array needs to be argc+1 for args, plus 1 for null sentinel */
-    newargs = (char **)calloc(argc+2, sizeof(char *));
-    newargs[0] = quoted(python);
-    newargs[1] = quoted(script);
-    memcpy(newargs+2, argv+1, (argc-1)*sizeof(char *));
-    newargs[argc+1] = NULL;
+    /* Argument array needs to be 
+       argc+1 for python executable,
+       plus 1 for possible python opts,
+       plus 1 for null sentinel */
+    newargs = (char **)calloc(argc+3, sizeof(char *));
+    newargsp = newargs;
+    *newargsp++ = quoted(python);
+    if (pyopt)
+      *newargsp++ = pyopt;
+    *newargsp++ = quoted(script);
+    for (i = 1; i < argc; i++)
+      *newargsp++ = quoted(argv[i]);
+    *newargsp++ = NULL;
 
     /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
     if (is_gui) {

Modified: sandbox/trunk/setuptools/setuptools/cli.exe
==============================================================================
Binary files. No diff available.

Modified: sandbox/trunk/setuptools/setuptools/gui.exe
==============================================================================
Binary files. No diff available.

Modified: sandbox/trunk/setuptools/setuptools/tests/__init__.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/tests/__init__.py	(original)
+++ sandbox/trunk/setuptools/setuptools/tests/__init__.py	Tue Aug 22 21:42:48 2006
@@ -14,11 +14,15 @@
 import sys, os.path
 
 def additional_tests():
-    import doctest
-    return doctest.DocFileSuite(
-        'api_tests.txt', optionflags=doctest.ELLIPSIS, package=__name__,
-    )
-
+    import doctest, unittest
+    suite = unittest.TestSuite((
+        doctest.DocFileSuite('api_tests.txt',
+                             optionflags=doctest.ELLIPSIS, package=__name__,
+                             ),
+        ))
+    if sys.platform == 'win32':
+        suite.addTest(doctest.DocFileSuite('win_script_wrapper.txt'))
+    return suite
 
 def makeSetup(**args):
     """Return distribution from 'setup(**args)', without executing commands"""


More information about the Python-checkins mailing list