File: C:/Users/fred/anaconda3/Lib/site-packages/anaconda_project/internal/windows_cmdline.py
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2016, Anaconda, Inc. All rights reserved.
#
# Licensed under the terms of the BSD 3-Clause License.
# The full license is in the file LICENSE.txt, distributed with this software.
# -----------------------------------------------------------------------------
"""Windows command line manipulation."""
from __future__ import absolute_import
import subprocess
class WindowsCommandLineException(Exception):
pass
def windows_split_command_line(command):
from ctypes import windll, c_int, POINTER, byref
from ctypes.wintypes import LPCWSTR, LPWSTR, HLOCAL
CommandLineToArgvW = windll.shell32.CommandLineToArgvW
CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)]
CommandLineToArgvW.restype = POINTER(LPWSTR)
LocalFree = windll.kernel32.LocalFree
LocalFree.argtypes = [HLOCAL]
LocalFree.restype = HLOCAL
argc = c_int(0)
argv = CommandLineToArgvW(command, byref(argc))
if not argv:
# The docs say CommandLineToArgvW returns NULL on error, but they
# don't describe any possible errors, so who knows when/if this happens.
# Maybe only on low memory or something?
raise WindowsCommandLineException("Windows could not parse command line: " + str(command))
try:
result = []
i = 0
while i < argc.value:
try:
result.append(str(argv[i]))
except UnicodeEncodeError as e:
message = ("Windows cannot represent this command line in its character encoding: " + command + ": " +
str(e))
raise WindowsCommandLineException(message)
i += 1
finally:
LocalFree(argv)
return result
def windows_join_command_line(args):
"""Combine an argv into a Windows command line.
Note: this can throw on some args you might pass in, but it should not throw
on args you got from windows_split_command_line, because those are args
that are representable as a command line. In other words, we throw on args
that windows_split_command_line won't be able to reproduce.
"""
if len(args) == 0:
raise WindowsCommandLineException("Windows has no way to encode an empty arg list as a command line")
# CommandLineToArgvW treats the first arg specially, which list2cmdline doesn't handle.
# If the first arg starts with a quote, CommandLineToArgvW returns up to the second quote,
# without interpreting any escapes. If the first arg doesn't start with a quote, then
# no quoting/escaping is processed, the first arg is just left alone including embedded
# quotes until a space (or control char) is encountered. So we can EITHER quote the whole
# thing (if it contains no quotes) in order to embed spaces; OR don't quote it to embed
# quotes but not spaces; but there is no way to have both quotes AND spaces in the first
# arg, as far as I can tell. Also there's no way the first arg can start with a quote.
if args[0].startswith('"'):
# note: windows_split_command_line would never give us this args[0], because it would
# strip off the leading quote
raise WindowsCommandLineException("Windows does not allow the first arg to start with a quote: " + args[0])
if '"' in args[0] and ' ' in args[0]:
# note: windows_split_command_line would never give us this args[0], because it would
# split on the space and make this two args
raise WindowsCommandLineException("Windows does not allow the first arg to have both quotes and spaces: " +
args[0])
first_arg = args[0]
if ' ' in first_arg:
first_arg = '"%s"' % first_arg
return first_arg + ' ' + subprocess.list2cmdline(args[1:])