##// END OF EJS Templates
Special version of arg_split for win32
Jörgen Stenarson -
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(s, posix=False):
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