eric6/DebugClients/Python/DebugUtilities.py

branch
multi_processing
changeset 7871
eb65864ca038
parent 7646
39e3db2b4936
child 7873
cb2badbdf26c
--- a/eric6/DebugClients/Python/DebugUtilities.py	Mon Dec 07 19:53:15 2020 +0100
+++ b/eric6/DebugClients/Python/DebugUtilities.py	Thu Dec 10 20:16:21 2020 +0100
@@ -228,6 +228,51 @@
     )
 
 
+def removeQuotesFromArgs(args):
+    """
+    Function to remove quotes from the arguments list.
+    
+    @param args list of arguments
+    @type list of str
+    @return list of unquoted strings
+    @rtype list of str
+    """
+    if isWindowsPlatform():
+        newArgs = []
+        for x in args:
+            if len(x) > 1 and x.startswith('"') and x.endswith('"'):
+                x = x[1:-1]
+            newArgs.append(x)
+        return newArgs
+    else:
+        return args
+
+
+def quoteArgs(args):
+    """
+    Function to quote the given list of arguments.
+    
+    @param args list of arguments to be quoted
+    @type list of str
+    @return list of quoted arguments
+    @rtype list of str
+    """
+    if isWindowsPlatform():
+        quotedArgs = []
+        for x in args:
+            if x.startswith('"') and x.endswith('"'):
+                quotedArgs.append(x)
+            else:
+                if ' ' in x:
+                    x = x.replace('"', '\\"')
+                    quotedArgs.append('"{0}"'.format(x))
+                else:
+                    quotedArgs.append(x)
+        return quotedArgs
+    else:
+        return args
+
+
 def patchArguments(debugClient, arguments, noRedirect=False):
     """
     Function to patch the arguments given to start a program in order to
@@ -243,6 +288,7 @@
     @rtype list of str
     """
     args = list(arguments[:])    # create a copy of the arguments list
+    args = removeQuotesFromArgs(args)
     
     # support for shebang line
     program = os.path.basename(args[0]).lower()
@@ -254,10 +300,8 @@
             # insert our interpreter as first argument
             args.insert(0, sys.executable)
     
-    # check for -c or -m invocation => debugging not supported yet
-    if "-c" in args:
-        cm_position = args.index("-c")
-    elif "-m" in args:
+    # check for -m invocation => debugging not supported yet
+    if "-m" in args:
         cm_position = args.index("-m")
     else:
         cm_position = 0
@@ -272,18 +316,25 @@
             found = False
         if found and cm_position < pos:
             # it belongs to the interpreter
-            return arguments
+            return quoteArgs(arguments)
     
     # extract list of interpreter arguments, i.e. all arguments before the
     # first one not starting with '-'.
     interpreter = args.pop(0)
     interpreterArgs = []
+    hasCode = False
     while args:
         if args[0].startswith("-"):
             if args[0] in ("-W", "-X"):
                 # take two elements off the list
                 interpreterArgs.append(args.pop(0))
                 interpreterArgs.append(args.pop(0))
+            elif args[0] == "-c":
+                # -c indicates code to be executed and ends the
+                # arguments list
+                args.pop(0)
+                hasCode = True
+                break
             else:
                 interpreterArgs.append(args.pop(0))
         else:
@@ -313,10 +364,123 @@
         modifiedArguments.append("--no-encoding")
     if debugClient.multiprocessSupport:
         modifiedArguments.append("--multiprocess")
+    if hasCode:
+        modifiedArguments.append("--code")
     modifiedArguments.append("--")
     # end the arguments for DebugClient
     
     # append the arguments for the program to be debugged
     modifiedArguments.extend(args)
+    modifiedArguments = quoteArgs(modifiedArguments)
     
     return modifiedArguments
+
+
+def stringToArgumentsWindows(args):
+    """
+    Function to prepare a string of arguments for Windows platform.
+    
+    @param args list of command arguments
+    @type str
+    @return list of command arguments
+    @rtype list of str
+    @exception RuntimeError raised to indicate an illegal arguments parsing
+        condition
+    """
+    # see http:#msdn.microsoft.com/en-us/library/a1y7w461.aspx
+    result = []
+    
+    DEFAULT = 0
+    ARG = 1
+    IN_DOUBLE_QUOTE = 2
+    
+    state = DEFAULT
+    backslashes = 0
+    buf = ''
+    
+    argsLen = len(args)
+    for i in range(argsLen):
+        ch = args[i]
+        if ch == '\\':
+            backslashes += 1
+            continue
+        elif backslashes != 0:
+            if ch == '"':
+                while backslashes >= 2:
+                    backslashes -= 2
+                    buf += '\\'
+                if backslashes == 1:
+                    if state == DEFAULT:
+                        state = ARG
+                    
+                    buf += '"'
+                    backslashes = 0
+                    continue
+            else:
+                # false alarm, treat passed backslashes literally...
+                if state == DEFAULT:
+                    state = ARG
+                
+                while backslashes > 0:
+                    backslashes -= 1
+                    buf += '\\'
+        
+        if ch in (' ', '\t'):
+            if state == DEFAULT:
+                # skip
+                continue
+            elif state == ARG:
+                state = DEFAULT
+                result.append(buf)
+                buf = ''
+                continue
+        
+        if state in (DEFAULT, ARG):
+            if ch == '"':
+                state = IN_DOUBLE_QUOTE
+            else:
+                state = ARG
+                buf += ch
+        
+        elif state == IN_DOUBLE_QUOTE:
+            if ch == '"':
+                if i + 1 < argsLen and args[i + 1] == '"':
+                    # Undocumented feature in Windows:
+                    # Two consecutive double quotes inside a double-quoted
+                    # argument are interpreted as a single double quote.
+                    buf += '"'
+                    i += 1
+                elif len(buf) == 0:
+                    result.append("\"\"")
+                    state = DEFAULT
+                else:
+                    state = ARG
+            else:
+                buf += ch
+        
+        else:
+            raise RuntimeError('Illegal condition')
+    
+    if len(buf) > 0 or state != DEFAULT:
+        result.append(buf)
+    
+    return result
+
+
+def patchArgumentStringWindows(debugClient, argStr):
+    """
+    Function to patch an argument string for Windows.
+    
+    @param debugClient reference to the debug client object
+    @type DebugClient
+    @param argStr argument string
+    @type str
+    @return patched argument string
+    @rtype str
+    """
+    args = stringToArgumentsWindows(argStr)
+    if not args or not isPythonProgram(args[0]):
+        return argStr
+    
+    argStr = ' '.join(patchArguments(debugClient, args))
+    return argStr

eric ide

mercurial