83 lines · python
1# -*- coding: utf-8 -*-2# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3# See https://llvm.org/LICENSE.txt for license information.4# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5""" This module implements basic shell escaping/unescaping methods. """6 7import re8import shlex9 10__all__ = ["encode", "decode"]11 12 13def encode(command):14 """Takes a command as list and returns a string."""15 16 def needs_quote(word):17 """Returns true if arguments needs to be protected by quotes.18 19 Previous implementation was shlex.split method, but that's not good20 for this job. Currently is running through the string with a basic21 state checking."""22 23 reserved = {24 " ",25 "$",26 "%",27 "&",28 "(",29 ")",30 "[",31 "]",32 "{",33 "}",34 "*",35 "|",36 "<",37 ">",38 "@",39 "?",40 "!",41 }42 state = 043 for current in word:44 if state == 0 and current in reserved:45 return True46 elif state == 0 and current == "\\":47 state = 148 elif state == 1 and current in reserved | {"\\"}:49 state = 050 elif state == 0 and current == '"':51 state = 252 elif state == 2 and current == '"':53 state = 054 elif state == 0 and current == "'":55 state = 356 elif state == 3 and current == "'":57 state = 058 return state != 059 60 def escape(word):61 """Do protect argument if that's needed."""62 63 table = {"\\": "\\\\", '"': '\\"'}64 escaped = "".join([table.get(c, c) for c in word])65 66 return '"' + escaped + '"' if needs_quote(word) else escaped67 68 return " ".join([escape(arg) for arg in command])69 70 71def decode(string):72 """Takes a command string and returns as a list."""73 74 def unescape(arg):75 """Gets rid of the escaping characters."""76 77 if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"':78 arg = arg[1:-1]79 return re.sub(r'\\(["\\])', r"\1", arg)80 return re.sub(r"\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])", r"\1", arg)81 82 return [unescape(arg) for arg in shlex.split(string)]83