Show More
@@ -22,7 +22,16 b' import shlex' | |||||
22 |
|
22 | |||
23 | # Our own |
|
23 | # Our own | |
24 | if sys.platform == 'win32': |
|
24 | if sys.platform == 'win32': | |
|
25 | import ctypes | |||
|
26 | from ctypes.wintypes import LPCWSTR, HLOCAL | |||
|
27 | from ctypes import c_int, POINTER | |||
25 | from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath |
|
28 | from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath | |
|
29 | CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW | |||
|
30 | CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)] | |||
|
31 | CommandLineToArgvW.res_types = [POINTER(LPCWSTR)] | |||
|
32 | LocalFree = ctypes.windll.kernel32.LocalFree | |||
|
33 | LocalFree.res_type = HLOCAL | |||
|
34 | LocalFree.arg_types = [HLOCAL] | |||
26 | else: |
|
35 | else: | |
27 | from ._process_posix import _find_cmd, system, getoutput |
|
36 | from ._process_posix import _find_cmd, system, getoutput | |
28 |
|
37 | |||
@@ -103,29 +112,42 b' def pycmd2argv(cmd):' | |||||
103 | else: |
|
112 | else: | |
104 | return [sys.executable, cmd] |
|
113 | return [sys.executable, cmd] | |
105 |
|
114 | |||
106 |
|
115 | if sys.platform == 'win32': | ||
107 |
def arg_split( |
|
116 | def arg_split(commandline, posix=False): | |
108 | """Split a command line's arguments in a shell-like manner. |
|
117 | """Split a command line's arguments in a shell-like manner. | |
109 |
|
118 | |||
110 | This is a modified version of the standard library's shlex.split() |
|
119 | This is a special version for windows that use a ctypes call to CommandLineToArgvW | |
111 | function, but with a default of posix=False for splitting, so that quotes |
|
120 | to do the argv splitting. The posix paramter is ignored. | |
112 | in inputs are respected.""" |
|
121 | """ | |
113 |
|
122 | argvn = c_int() | ||
114 | # Unfortunately, python's shlex module is buggy with unicode input: |
|
123 | result_pointer = CommandLineToArgvW(py3compat.str_to_unicode(commandline.lstrip()), ctypes.byref(argvn)) | |
115 | # http://bugs.python.org/issue1170 |
|
124 | result_array_type = LPCWSTR * argvn.value | |
116 | # At least encoding the input when it's unicode seems to help, but there |
|
125 | result = [arg for arg in result_array_type.from_address(result_pointer)] | |
117 | # may be more problems lurking. Apparently this is fixed in python3. |
|
126 | retval = LocalFree(result_pointer) | |
118 | is_unicode = False |
|
127 | return result | |
119 | if (not py3compat.PY3) and isinstance(s, unicode): |
|
128 | else: | |
120 | is_unicode = True |
|
129 | def arg_split(s, posix=False): | |
121 | s = s.encode('utf-8') |
|
130 | """Split a command line's arguments in a shell-like manner. | |
122 | lex = shlex.shlex(s, posix=posix) |
|
131 | ||
123 | lex.whitespace_split = True |
|
132 | This is a modified version of the standard library's shlex.split() | |
124 | tokens = list(lex) |
|
133 | function, but with a default of posix=False for splitting, so that quotes | |
125 | if is_unicode: |
|
134 | in inputs are respected.""" | |
126 | # Convert the tokens back to unicode. |
|
135 | ||
127 | tokens = [x.decode('utf-8') for x in tokens] |
|
136 | # Unfortunately, python's shlex module is buggy with unicode input: | |
128 | return tokens |
|
137 | # http://bugs.python.org/issue1170 | |
|
138 | # At least encoding the input when it's unicode seems to help, but there | |||
|
139 | # may be more problems lurking. Apparently this is fixed in python3. | |||
|
140 | is_unicode = False | |||
|
141 | if (not py3compat.PY3) and isinstance(s, unicode): | |||
|
142 | is_unicode = True | |||
|
143 | s = s.encode('utf-8') | |||
|
144 | lex = shlex.shlex(s, posix=posix) | |||
|
145 | lex.whitespace_split = True | |||
|
146 | tokens = list(lex) | |||
|
147 | if is_unicode: | |||
|
148 | # Convert the tokens back to unicode. | |||
|
149 | tokens = [x.decode('utf-8') for x in tokens] | |||
|
150 | return tokens | |||
129 |
|
151 | |||
130 |
|
152 | |||
131 | def abbrev_cwd(): |
|
153 | def abbrev_cwd(): |
@@ -62,12 +62,25 b' def test_find_cmd_fail():' | |||||
62 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') |
|
62 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') | |
63 |
|
63 | |||
64 |
|
64 | |||
|
65 | @dec.skip_win32 | |||
65 | def test_arg_split(): |
|
66 | def test_arg_split(): | |
66 | """Ensure that argument lines are correctly split like in a shell.""" |
|
67 | """Ensure that argument lines are correctly split like in a shell.""" | |
67 | tests = [['hi', ['hi']], |
|
68 | tests = [['hi', ['hi']], | |
68 | [u'hi', [u'hi']], |
|
69 | [u'hi', [u'hi']], | |
69 | ['hello there', ['hello', 'there']], |
|
70 | ['hello there', ['hello', 'there']], | |
70 | [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']], |
|
71 | # [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']], | |
|
72 | ['something "with quotes"', ['something', '"with quotes"']], | |||
|
73 | ] | |||
|
74 | for argstr, argv in tests: | |||
|
75 | nt.assert_equal(arg_split(argstr), argv) | |||
|
76 | ||||
|
77 | @dec.skip_win32 | |||
|
78 | def test_arg_split_win32(): | |||
|
79 | """Ensure that argument lines are correctly split like in a shell.""" | |||
|
80 | tests = [['hi', ['hi']], | |||
|
81 | [u'hi', [u'hi']], | |||
|
82 | ['hello there', ['hello', 'there']], | |||
|
83 | # [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']], | |||
71 | ['something "with quotes"', ['something', '"with quotes"']], |
|
84 | ['something "with quotes"', ['something', '"with quotes"']], | |
72 | ] |
|
85 | ] | |
73 | for argstr, argv in tests: |
|
86 | for argstr, argv in tests: |
General Comments 0
You need to be logged in to leave comments.
Login now