1# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Safely evaluate Python string literals without using eval()."""
5
6import re
7
8simple_escapes = {"a": "\a",
9                  "b": "\b",
10                  "f": "\f",
11                  "n": "\n",
12                  "r": "\r",
13                  "t": "\t",
14                  "v": "\v",
15                  "'": "'",
16                  '"': '"',
17                  "\\": "\\"}
18
19def escape(m):
20    all, tail = m.group(0, 1)
21    assert all.startswith("\\")
22    esc = simple_escapes.get(tail)
23    if esc is not None:
24        return esc
25    if tail.startswith("x"):
26        hexes = tail[1:]
27        if len(hexes) < 2:
28            raise ValueError("invalid hex string escape ('\\%s')" % tail)
29        try:
30            i = int(hexes, 16)
31        except ValueError:
32            raise ValueError("invalid hex string escape ('\\%s')" % tail)
33    else:
34        try:
35            i = int(tail, 8)
36        except ValueError:
37            raise ValueError("invalid octal string escape ('\\%s')" % tail)
38    return chr(i)
39
40def evalString(s):
41    assert s.startswith("'") or s.startswith('"'), repr(s[:1])
42    q = s[0]
43    if s[:3] == q*3:
44        q = q*3
45    assert s.endswith(q), repr(s[-len(q):])
46    assert len(s) >= 2*len(q)
47    s = s[len(q):-len(q)]
48    return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s)
49
50def test():
51    for i in range(256):
52        c = chr(i)
53        s = repr(c)
54        e = evalString(s)
55        if e != c:
56            print(i, c, s, e)
57
58
59if __name__ == "__main__":
60    test()
61