Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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-exception |
||
5 | """ This module implements basic shell escaping/unescaping methods. """ |
||
6 | |||
7 | import re |
||
8 | import shlex |
||
9 | |||
10 | __all__ = ['encode', 'decode'] |
||
11 | |||
12 | |||
13 | def 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 good |
||
20 | for this job. Currently is running through the string with a basic |
||
21 | state checking. """ |
||
22 | |||
23 | reserved = {' ', '$', '%', '&', '(', ')', '[', ']', '{', '}', '*', '|', |
||
24 | '<', '>', '@', '?', '!'} |
||
25 | state = 0 |
||
26 | for current in word: |
||
27 | if state == 0 and current in reserved: |
||
28 | return True |
||
29 | elif state == 0 and current == '\\': |
||
30 | state = 1 |
||
31 | elif state == 1 and current in reserved | {'\\'}: |
||
32 | state = 0 |
||
33 | elif state == 0 and current == '"': |
||
34 | state = 2 |
||
35 | elif state == 2 and current == '"': |
||
36 | state = 0 |
||
37 | elif state == 0 and current == "'": |
||
38 | state = 3 |
||
39 | elif state == 3 and current == "'": |
||
40 | state = 0 |
||
41 | return state != 0 |
||
42 | |||
43 | def escape(word): |
||
44 | """ Do protect argument if that's needed. """ |
||
45 | |||
46 | table = {'\\': '\\\\', '"': '\\"'} |
||
47 | escaped = ''.join([table.get(c, c) for c in word]) |
||
48 | |||
49 | return '"' + escaped + '"' if needs_quote(word) else escaped |
||
50 | |||
51 | return " ".join([escape(arg) for arg in command]) |
||
52 | |||
53 | |||
54 | def decode(string): |
||
55 | """ Takes a command string and returns as a list. """ |
||
56 | |||
57 | def unescape(arg): |
||
58 | """ Gets rid of the escaping characters. """ |
||
59 | |||
60 | if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"': |
||
61 | arg = arg[1:-1] |
||
62 | return re.sub(r'\\(["\\])', r'\1', arg) |
||
63 | return re.sub(r'\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])', r'\1', arg) |
||
64 | |||
65 | return [unescape(arg) for arg in shlex.split(string)] |