226 isExecutable(program) and |
226 isExecutable(program) and |
227 startsWithShebang(program) |
227 startsWithShebang(program) |
228 ) |
228 ) |
229 |
229 |
230 |
230 |
|
231 def removeQuotesFromArgs(args): |
|
232 """ |
|
233 Function to remove quotes from the arguments list. |
|
234 |
|
235 @param args list of arguments |
|
236 @type list of str |
|
237 @return list of unquoted strings |
|
238 @rtype list of str |
|
239 """ |
|
240 if isWindowsPlatform(): |
|
241 newArgs = [] |
|
242 for x in args: |
|
243 if len(x) > 1 and x.startswith('"') and x.endswith('"'): |
|
244 x = x[1:-1] |
|
245 newArgs.append(x) |
|
246 return newArgs |
|
247 else: |
|
248 return args |
|
249 |
|
250 |
|
251 def quoteArgs(args): |
|
252 """ |
|
253 Function to quote the given list of arguments. |
|
254 |
|
255 @param args list of arguments to be quoted |
|
256 @type list of str |
|
257 @return list of quoted arguments |
|
258 @rtype list of str |
|
259 """ |
|
260 if isWindowsPlatform(): |
|
261 quotedArgs = [] |
|
262 for x in args: |
|
263 if x.startswith('"') and x.endswith('"'): |
|
264 quotedArgs.append(x) |
|
265 else: |
|
266 if ' ' in x: |
|
267 x = x.replace('"', '\\"') |
|
268 quotedArgs.append('"{0}"'.format(x)) |
|
269 else: |
|
270 quotedArgs.append(x) |
|
271 return quotedArgs |
|
272 else: |
|
273 return args |
|
274 |
|
275 |
231 def patchArguments(debugClient, arguments, noRedirect=False): |
276 def patchArguments(debugClient, arguments, noRedirect=False): |
232 """ |
277 """ |
233 Function to patch the arguments given to start a program in order to |
278 Function to patch the arguments given to start a program in order to |
234 execute it in our debugger. |
279 execute it in our debugger. |
235 |
280 |
241 @type bool |
286 @type bool |
242 @return modified argument list |
287 @return modified argument list |
243 @rtype list of str |
288 @rtype list of str |
244 """ |
289 """ |
245 args = list(arguments[:]) # create a copy of the arguments list |
290 args = list(arguments[:]) # create a copy of the arguments list |
|
291 args = removeQuotesFromArgs(args) |
246 |
292 |
247 # support for shebang line |
293 # support for shebang line |
248 program = os.path.basename(args[0]).lower() |
294 program = os.path.basename(args[0]).lower() |
249 for pyname in PYTHON_NAMES: |
295 for pyname in PYTHON_NAMES: |
250 if pyname in program: |
296 if pyname in program: |
252 else: |
298 else: |
253 if not isWindowsPlatform() and startsWithShebang(args[0]): |
299 if not isWindowsPlatform() and startsWithShebang(args[0]): |
254 # insert our interpreter as first argument |
300 # insert our interpreter as first argument |
255 args.insert(0, sys.executable) |
301 args.insert(0, sys.executable) |
256 |
302 |
257 # check for -c or -m invocation => debugging not supported yet |
303 # check for -m invocation => debugging not supported yet |
258 if "-c" in args: |
304 if "-m" in args: |
259 cm_position = args.index("-c") |
|
260 elif "-m" in args: |
|
261 cm_position = args.index("-m") |
305 cm_position = args.index("-m") |
262 else: |
306 else: |
263 cm_position = 0 |
307 cm_position = 0 |
264 if cm_position > 0: |
308 if cm_position > 0: |
265 # check if it belongs to the interpreter or program |
309 # check if it belongs to the interpreter or program |
270 break |
314 break |
271 else: |
315 else: |
272 found = False |
316 found = False |
273 if found and cm_position < pos: |
317 if found and cm_position < pos: |
274 # it belongs to the interpreter |
318 # it belongs to the interpreter |
275 return arguments |
319 return quoteArgs(arguments) |
276 |
320 |
277 # extract list of interpreter arguments, i.e. all arguments before the |
321 # extract list of interpreter arguments, i.e. all arguments before the |
278 # first one not starting with '-'. |
322 # first one not starting with '-'. |
279 interpreter = args.pop(0) |
323 interpreter = args.pop(0) |
280 interpreterArgs = [] |
324 interpreterArgs = [] |
|
325 hasCode = False |
281 while args: |
326 while args: |
282 if args[0].startswith("-"): |
327 if args[0].startswith("-"): |
283 if args[0] in ("-W", "-X"): |
328 if args[0] in ("-W", "-X"): |
284 # take two elements off the list |
329 # take two elements off the list |
285 interpreterArgs.append(args.pop(0)) |
330 interpreterArgs.append(args.pop(0)) |
286 interpreterArgs.append(args.pop(0)) |
331 interpreterArgs.append(args.pop(0)) |
|
332 elif args[0] == "-c": |
|
333 # -c indicates code to be executed and ends the |
|
334 # arguments list |
|
335 args.pop(0) |
|
336 hasCode = True |
|
337 break |
287 else: |
338 else: |
288 interpreterArgs.append(args.pop(0)) |
339 interpreterArgs.append(args.pop(0)) |
289 else: |
340 else: |
290 break |
341 break |
291 |
342 |
311 modifiedArguments.append("-n") |
362 modifiedArguments.append("-n") |
312 if noencoding: |
363 if noencoding: |
313 modifiedArguments.append("--no-encoding") |
364 modifiedArguments.append("--no-encoding") |
314 if debugClient.multiprocessSupport: |
365 if debugClient.multiprocessSupport: |
315 modifiedArguments.append("--multiprocess") |
366 modifiedArguments.append("--multiprocess") |
|
367 if hasCode: |
|
368 modifiedArguments.append("--code") |
316 modifiedArguments.append("--") |
369 modifiedArguments.append("--") |
317 # end the arguments for DebugClient |
370 # end the arguments for DebugClient |
318 |
371 |
319 # append the arguments for the program to be debugged |
372 # append the arguments for the program to be debugged |
320 modifiedArguments.extend(args) |
373 modifiedArguments.extend(args) |
|
374 modifiedArguments = quoteArgs(modifiedArguments) |
321 |
375 |
322 return modifiedArguments |
376 return modifiedArguments |
|
377 |
|
378 |
|
379 def stringToArgumentsWindows(args): |
|
380 """ |
|
381 Function to prepare a string of arguments for Windows platform. |
|
382 |
|
383 @param args list of command arguments |
|
384 @type str |
|
385 @return list of command arguments |
|
386 @rtype list of str |
|
387 @exception RuntimeError raised to indicate an illegal arguments parsing |
|
388 condition |
|
389 """ |
|
390 # see http:#msdn.microsoft.com/en-us/library/a1y7w461.aspx |
|
391 result = [] |
|
392 |
|
393 DEFAULT = 0 |
|
394 ARG = 1 |
|
395 IN_DOUBLE_QUOTE = 2 |
|
396 |
|
397 state = DEFAULT |
|
398 backslashes = 0 |
|
399 buf = '' |
|
400 |
|
401 argsLen = len(args) |
|
402 for i in range(argsLen): |
|
403 ch = args[i] |
|
404 if ch == '\\': |
|
405 backslashes += 1 |
|
406 continue |
|
407 elif backslashes != 0: |
|
408 if ch == '"': |
|
409 while backslashes >= 2: |
|
410 backslashes -= 2 |
|
411 buf += '\\' |
|
412 if backslashes == 1: |
|
413 if state == DEFAULT: |
|
414 state = ARG |
|
415 |
|
416 buf += '"' |
|
417 backslashes = 0 |
|
418 continue |
|
419 else: |
|
420 # false alarm, treat passed backslashes literally... |
|
421 if state == DEFAULT: |
|
422 state = ARG |
|
423 |
|
424 while backslashes > 0: |
|
425 backslashes -= 1 |
|
426 buf += '\\' |
|
427 |
|
428 if ch in (' ', '\t'): |
|
429 if state == DEFAULT: |
|
430 # skip |
|
431 continue |
|
432 elif state == ARG: |
|
433 state = DEFAULT |
|
434 result.append(buf) |
|
435 buf = '' |
|
436 continue |
|
437 |
|
438 if state in (DEFAULT, ARG): |
|
439 if ch == '"': |
|
440 state = IN_DOUBLE_QUOTE |
|
441 else: |
|
442 state = ARG |
|
443 buf += ch |
|
444 |
|
445 elif state == IN_DOUBLE_QUOTE: |
|
446 if ch == '"': |
|
447 if i + 1 < argsLen and args[i + 1] == '"': |
|
448 # Undocumented feature in Windows: |
|
449 # Two consecutive double quotes inside a double-quoted |
|
450 # argument are interpreted as a single double quote. |
|
451 buf += '"' |
|
452 i += 1 |
|
453 elif len(buf) == 0: |
|
454 result.append("\"\"") |
|
455 state = DEFAULT |
|
456 else: |
|
457 state = ARG |
|
458 else: |
|
459 buf += ch |
|
460 |
|
461 else: |
|
462 raise RuntimeError('Illegal condition') |
|
463 |
|
464 if len(buf) > 0 or state != DEFAULT: |
|
465 result.append(buf) |
|
466 |
|
467 return result |
|
468 |
|
469 |
|
470 def patchArgumentStringWindows(debugClient, argStr): |
|
471 """ |
|
472 Function to patch an argument string for Windows. |
|
473 |
|
474 @param debugClient reference to the debug client object |
|
475 @type DebugClient |
|
476 @param argStr argument string |
|
477 @type str |
|
478 @return patched argument string |
|
479 @rtype str |
|
480 """ |
|
481 args = stringToArgumentsWindows(argStr) |
|
482 if not args or not isPythonProgram(args[0]): |
|
483 return argStr |
|
484 |
|
485 argStr = ' '.join(patchArguments(debugClient, args)) |
|
486 return argStr |