# -*- coding: utf-8 -*- # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. """ This module implements basic shell escaping/unescaping methods. """ import re import shlex __all__ = ['encode', 'decode'] def encode(command): """ Takes a command as list and returns a string. """ def needs_quote(word): """ Returns true if arguments needs to be protected by quotes. Previous implementation was shlex.split method, but that's not good for this job. Currently is running through the string with a basic state checking. """ reserved = {' ', '$', '%', '&', '(', ')', '[', ']', '{', '}', '*', '|', '<', '>', '@', '?', '!'} state = 0 for current in word: if state == 0 and current in reserved: return True elif state == 0 and current == '\\': state = 1 elif state == 1 and current in reserved | {'\\'}: state = 0 elif state == 0 and current == '"': state = 2 elif state == 2 and current == '"': state = 0 elif state == 0 and current == "'": state = 3 elif state == 3 and current == "'": state = 0 return state != 0 def escape(word): """ Do protect argument if that's needed. """ table = {'\\': '\\\\', '"': '\\"'} escaped = ''.join([table.get(c, c) for c in word]) return '"' + escaped + '"' if needs_quote(word) else escaped return " ".join([escape(arg) for arg in command]) def decode(string): """ Takes a command string and returns as a list. """ def unescape(arg): """ Gets rid of the escaping characters. """ if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"': arg = arg[1:-1] return re.sub(r'\\(["\\])', r'\1', arg) return re.sub(r'\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])', r'\1', arg) return [unescape(arg) for arg in shlex.split(string)]