1*67e74705SXin Li# -*- coding: utf-8 -*- 2*67e74705SXin Li# The LLVM Compiler Infrastructure 3*67e74705SXin Li# 4*67e74705SXin Li# This file is distributed under the University of Illinois Open Source 5*67e74705SXin Li# License. See LICENSE.TXT for details. 6*67e74705SXin Li""" This module implements basic shell escaping/unescaping methods. """ 7*67e74705SXin Li 8*67e74705SXin Liimport re 9*67e74705SXin Liimport shlex 10*67e74705SXin Li 11*67e74705SXin Li__all__ = ['encode', 'decode'] 12*67e74705SXin Li 13*67e74705SXin Li 14*67e74705SXin Lidef encode(command): 15*67e74705SXin Li """ Takes a command as list and returns a string. """ 16*67e74705SXin Li 17*67e74705SXin Li def needs_quote(word): 18*67e74705SXin Li """ Returns true if arguments needs to be protected by quotes. 19*67e74705SXin Li 20*67e74705SXin Li Previous implementation was shlex.split method, but that's not good 21*67e74705SXin Li for this job. Currently is running through the string with a basic 22*67e74705SXin Li state checking. """ 23*67e74705SXin Li 24*67e74705SXin Li reserved = {' ', '$', '%', '&', '(', ')', '[', ']', '{', '}', '*', '|', 25*67e74705SXin Li '<', '>', '@', '?', '!'} 26*67e74705SXin Li state = 0 27*67e74705SXin Li for current in word: 28*67e74705SXin Li if state == 0 and current in reserved: 29*67e74705SXin Li return True 30*67e74705SXin Li elif state == 0 and current == '\\': 31*67e74705SXin Li state = 1 32*67e74705SXin Li elif state == 1 and current in reserved | {'\\'}: 33*67e74705SXin Li state = 0 34*67e74705SXin Li elif state == 0 and current == '"': 35*67e74705SXin Li state = 2 36*67e74705SXin Li elif state == 2 and current == '"': 37*67e74705SXin Li state = 0 38*67e74705SXin Li elif state == 0 and current == "'": 39*67e74705SXin Li state = 3 40*67e74705SXin Li elif state == 3 and current == "'": 41*67e74705SXin Li state = 0 42*67e74705SXin Li return state != 0 43*67e74705SXin Li 44*67e74705SXin Li def escape(word): 45*67e74705SXin Li """ Do protect argument if that's needed. """ 46*67e74705SXin Li 47*67e74705SXin Li table = {'\\': '\\\\', '"': '\\"'} 48*67e74705SXin Li escaped = ''.join([table.get(c, c) for c in word]) 49*67e74705SXin Li 50*67e74705SXin Li return '"' + escaped + '"' if needs_quote(word) else escaped 51*67e74705SXin Li 52*67e74705SXin Li return " ".join([escape(arg) for arg in command]) 53*67e74705SXin Li 54*67e74705SXin Li 55*67e74705SXin Lidef decode(string): 56*67e74705SXin Li """ Takes a command string and returns as a list. """ 57*67e74705SXin Li 58*67e74705SXin Li def unescape(arg): 59*67e74705SXin Li """ Gets rid of the escaping characters. """ 60*67e74705SXin Li 61*67e74705SXin Li if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"': 62*67e74705SXin Li arg = arg[1:-1] 63*67e74705SXin Li return re.sub(r'\\(["\\])', r'\1', arg) 64*67e74705SXin Li return re.sub(r'\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])', r'\1', arg) 65*67e74705SXin Li 66*67e74705SXin Li return [unescape(arg) for arg in shlex.split(string)] 67