23
23
__author__ = 'Wouter van Oortmerssen'
24
24
25
25
import argparse
26
+ import ctypes
26
27
import json
27
28
import os
29
+ import platform
28
30
import sys
29
31
from xml .etree import ElementTree
30
32
@@ -218,6 +220,33 @@ def indent(elem, level=0):
218
220
elem .tail = i
219
221
220
222
223
+ def argv_as_unicode_win32 ():
224
+ """Returns unicode command line arguments on windows.
225
+ """
226
+
227
+ get_command_line_w = ctypes .cdll .kernel32 .GetCommandLineW
228
+ get_command_line_w .restype = ctypes .wintypes .LPCWSTR
229
+
230
+ # CommandLineToArgvW parses the Unicode command line
231
+ command_line_to_argv_w = ctypes .windll .shell32 .CommandLineToArgvW
232
+ command_line_to_argv_w .argtypes = [
233
+ ctypes .wintypes .LPCWSTR ,
234
+ ctypes .wintypes .POINTER (ctypes .wintypes .c_int )
235
+ ]
236
+ command_line_to_argv_w .restype = ctypes .wintypes .POINTER (
237
+ ctypes .wintypes .LPWSTR )
238
+
239
+ argc = ctypes .wintypes .c_int (0 )
240
+ argv = command_line_to_argv_w (get_command_line_w (), argc )
241
+
242
+ # Strip the python executable from the arguments if it exists
243
+ # (It would be listed as the first argument on the windows command line, but
244
+ # not in the arguments to the python script)
245
+ sys_argv_len = len (sys .argv )
246
+ return [unicode (argv [i ]) for i in
247
+ range (argc .value - sys_argv_len , argc .value )]
248
+
249
+
221
250
def main ():
222
251
parser = argparse .ArgumentParser (
223
252
description = ((
@@ -254,6 +283,11 @@ def main():
254
283
default = False ,
255
284
required = False )
256
285
286
+ # python 2 on Windows doesn't handle unicode arguments well, so we need to
287
+ # pre-process the command line arguments before trying to parse them.
288
+ if platform .system () == 'Windows' :
289
+ sys .argv = argv_as_unicode_win32 ()
290
+
257
291
args = parser .parse_args ()
258
292
259
293
if args .plist :
@@ -264,12 +298,18 @@ def main():
264
298
output_filename = DEFAULT_OUTPUT_FILENAME
265
299
266
300
if args .i :
267
- input_filename = args .i
301
+ input_filename_raw = args .i
302
+ # Encode the input string (type unicode) as a normal string (type str)
303
+ # using the 'utf-8' encoding so that it can be worked with the same as
304
+ # input names from other sources (like the defaults).
305
+ input_filename = input_filename_raw .encode ('utf-8' )
268
306
269
307
if args .o :
270
308
output_filename = args .o
271
309
272
- with open (input_filename , 'r' ) as ifile :
310
+ # Decode the filename to a unicode string using the 'utf-8' encoding to
311
+ # properly handle filepaths with unicode characters in them.
312
+ with open (input_filename .decode ('utf-8' ), 'r' ) as ifile :
273
313
file_string = ifile .read ()
274
314
275
315
json_string = None
@@ -387,7 +427,9 @@ def main():
387
427
if args .l :
388
428
for package in packages :
389
429
if package :
390
- sys .stdout .write (package + '\n ' )
430
+ # Encode the output string in case the system's default encoding differs
431
+ # from the encoding of the string being printed.
432
+ sys .stdout .write ((package + '\n ' ).encode (sys .getdefaultencoding ()))
391
433
else :
392
434
path = os .path .dirname (output_filename )
393
435
0 commit comments