diff -r ab8f95bc7d2d -r eb65864ca038 eric6/DebugClients/Python/DebugUtilities.py --- 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