88 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Helper functions for interacting with the shell, and consuming shell-style
 | 
						|
parameters provided in config files.
 | 
						|
"""
 | 
						|
import os
 | 
						|
import shlex
 | 
						|
import subprocess
 | 
						|
 | 
						|
__all__ = ['WindowsParser', 'PosixParser', 'NativeParser']
 | 
						|
 | 
						|
 | 
						|
class CommandLineParser:
 | 
						|
    """
 | 
						|
    An object that knows how to split and join command-line arguments.
 | 
						|
 | 
						|
    It must be true that ``argv == split(join(argv))`` for all ``argv``.
 | 
						|
    The reverse neednt be true - `join(split(cmd))` may result in the addition
 | 
						|
    or removal of unnecessary escaping.
 | 
						|
    """
 | 
						|
    @staticmethod
 | 
						|
    def join(argv):
 | 
						|
        """ Join a list of arguments into a command line string """
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def split(cmd):
 | 
						|
        """ Split a command line string into a list of arguments """
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
 | 
						|
class WindowsParser:
 | 
						|
    """
 | 
						|
    The parsing behavior used by `subprocess.call("string")` on Windows, which
 | 
						|
    matches the Microsoft C/C++ runtime.
 | 
						|
 | 
						|
    Note that this is _not_ the behavior of cmd.
 | 
						|
    """
 | 
						|
    @staticmethod
 | 
						|
    def join(argv):
 | 
						|
        # note that list2cmdline is specific to the windows syntax
 | 
						|
        return subprocess.list2cmdline(argv)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def split(cmd):
 | 
						|
        import ctypes  # guarded import for systems without ctypes
 | 
						|
        try:
 | 
						|
            ctypes.windll
 | 
						|
        except AttributeError:
 | 
						|
            raise NotImplementedError
 | 
						|
 | 
						|
        # Windows has special parsing rules for the executable (no quotes),
 | 
						|
        # that we do not care about - insert a dummy element
 | 
						|
        if not cmd:
 | 
						|
            return []
 | 
						|
        cmd = 'dummy ' + cmd
 | 
						|
 | 
						|
        CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
 | 
						|
        CommandLineToArgvW.restype = ctypes.POINTER(ctypes.c_wchar_p)
 | 
						|
        CommandLineToArgvW.argtypes = (ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_int))
 | 
						|
 | 
						|
        nargs = ctypes.c_int()
 | 
						|
        lpargs = CommandLineToArgvW(cmd, ctypes.byref(nargs))
 | 
						|
        args = [lpargs[i] for i in range(nargs.value)]
 | 
						|
        assert not ctypes.windll.kernel32.LocalFree(lpargs)
 | 
						|
 | 
						|
        # strip the element we inserted
 | 
						|
        assert args[0] == "dummy"
 | 
						|
        return args[1:]
 | 
						|
 | 
						|
 | 
						|
class PosixParser:
 | 
						|
    """
 | 
						|
    The parsing behavior used by `subprocess.call("string", shell=True)` on Posix.
 | 
						|
    """
 | 
						|
    @staticmethod
 | 
						|
    def join(argv):
 | 
						|
        return ' '.join(shlex.quote(arg) for arg in argv)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def split(cmd):
 | 
						|
        return shlex.split(cmd, posix=True)
 | 
						|
 | 
						|
 | 
						|
if os.name == 'nt':
 | 
						|
    NativeParser = WindowsParser
 | 
						|
elif os.name == 'posix':
 | 
						|
    NativeParser = PosixParser
 |